#pragma once
#include "base.hpp"
#include "fields.hpp"
#include "my_tool.hpp"

/*
                                                            -->  RpcRequest
                                     -->  JsonRequest       -->  TopicRequest
                                                            -->  ServiceRequest
    BaseMessage  --> jsonMessage

                                                            -->  RpcResPonse
                                     -->  JsonResPonse      -->  TopicResPonse
                                                            -->  ServiceResPonse
*/

namespace jsonrpc
{
    typedef std::pair<std::string, int> Address; // Service的主机地址信息

    // 实现心跳包
    class HeartbeatMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<HeartbeatMessage>;
        virtual std::string serialize() override {return "";} 
        virtual bool unserialize(const std::string &msg)override{return true;}
        virtual bool check()override{ return true;}
    };

    class jsonMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<jsonMessage>;

        virtual std::string serialize() override
        {
            std::string body;
            bool ret = JsonUtil::serialize(_body, body); // json对象 + 字符串(将json对象变为字符串)
            if (ret == false)
                return std::string();

            return body;
        }

        virtual bool unserialize(const std::string &msg) override
        {
            bool ret = JsonUtil::unserialize(msg, _body); // 字符串 + json对象(将字符串变为json对象)
            if (ret == false)
                return false;
            
            if (!_body.isObject())
            {
                ELOG("反序列化的消息不是对象类型");
                return false;
            }
            return true;
        }

        // 不同消息的检测不同 -- 先不写
        virtual bool check() = 0;

    protected:
        Json::Value _body;
    };

    // 自己所支持的3类功能
    // 1.1 JsonRequest
    class JsonRequest : public jsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
    };

    // 1.2 JsonResPonse
    class JsonResPonse : public jsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonResPonse>;
        virtual bool check() override
        {
            // 大部分响应都只有状态码
            // 判断响应状态是否存在, 类型是否正确
            // Json中有isNull()函数, 可以用其判断是否包含有指定名称的字段
            if (_body[KEY_RCODE].isNull() == true)
            {
                ELOG("响应中无响应状态码");
                return false;
            }

            if (_body[KEY_RCODE].isIntegral() == false)
            {
                ELOG("响应状态码类型错误, 不是整型");
                return false;
            }
            return true;
        }

        virtual RCode rcode() { return (RCode)_body[KEY_RCODE].asInt();}
        virtual void setRCode(RCode rcode) {_body[KEY_RCODE] = (int)rcode;}
    };

    // 2.1.1 RPCRequest  -- method + parameters
    class RpcRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RpcRequest>;
        virtual bool check() override
        {
            // 做类型检查
            if (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false)
            {
                ELOG("RPC请求 -- method不存在 或 method类型错误");
                return false;
            }

            if (_body[KEY_PARAMS].isNull() == true || _body[KEY_PARAMS].isObject() == false)
            {
                ELOG("RPC请求 -- parameters不存在 或 parameters类型错误");
                return false;
            }
            return true;
        }

        // 给服务端提供 -- 提取出方法 + 参数
        // 给客户端提供 -- 设置出方法 + 参数
        std::string method() { return _body[KEY_METHOD].asString(); }
        Json::Value parameters() { return _body[KEY_PARAMS]; }

        void setMethod(const std::string &method) { _body[KEY_METHOD] = method; }
        void setparameters(const Json::Value &parameters) { _body[KEY_PARAMS] = parameters; }
    };

    // 2.1.2  TopicRequest   -- key  + optype + msg
    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;
        // 做类型检查
        virtual bool check() override
        {
            if (_body[KEY_TOPIC_KEY].isNull() == true || _body[KEY_TOPIC_KEY].isString() == false)
            {
                ELOG("主题请求 -- topic_key(方法)不存在 或 topic_key类型错误");
                return false;
            }

            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                ELOG("主题请求 -- optype不存在 或 optype类型错误");
                return false;
            }

            if (_body[KEY_OPTYPE].asInt() == (int)TopicOptype::TOPIC_PUBLISH && 
               (_body[KEY_TOPIC_MSG].isNull() == true || _body[KEY_TOPIC_MSG].isString() == false))
            {
                ELOG("主题请求 -- msg不存在 或 msg类型错误");
                return false;
            }
            return true;
        }

        // 给服务端提供 -- 提取出 key + optype + msg
        // 给客户端提供 -- 设置出 key + optype + msg
        std::string topicKey(){ return _body[KEY_TOPIC_KEY].asString(); }
        TopicOptype optype(){ return (TopicOptype)_body[KEY_OPTYPE].asInt(); }
        std::string topicMsg(){ return _body[KEY_TOPIC_MSG].asString(); }

        void setTopicKey(const std::string key){ _body[KEY_TOPIC_KEY] = key;}
        void setOptype(TopicOptype op){ _body[KEY_OPTYPE] = (int)op;}
        void setTopicMsg(const std::string msg){ _body[KEY_TOPIC_MSG] = msg;}
    };

    // 2.1.3  ServiceRequest    -- method + host + optype
    class ServiceRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;
        // 类型检查
        virtual bool check() override
        {
            if (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false)
            {
                ELOG("服务请求 -- method不存在 或 method类型错误");
                return false;
            }

            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                ELOG("服务请求 -- optype不存在 或 optype类型错误");
                return false;
            }

            if (_body[KEY_OPTYPE].asInt() != (int)(ServiceOptype::SERVICE_DISCOVERY) &&
                (_body[KEY_HOST].isNull() == true ||_body[KEY_HOST].isObject() == false 
             || _body[KEY_HOST][KEY_HOST_IP].isNull() == true ||  _body[KEY_HOST][KEY_HOST_IP].isString() == false
             || _body[KEY_HOST][KEY_HOST_PORT].isNull() == true || _body[KEY_HOST][KEY_HOST_PORT].isIntegral() == false)) 
            {
                ELOG("服务请求 -- 中主机地址信息错误！");
                return false;
            }
            return true;
        }

        // 给服务端提供 -- 提取出 method + host + optype
        // 给客户端提供 -- 设置出 method + host + optype
        std::string method(){return _body[KEY_METHOD].asString();}
        ServiceOptype optype(){return (ServiceOptype)_body[KEY_OPTYPE].asInt();}
        Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }

        void setMethod(const std::string method){ _body[KEY_METHOD] = method;}
        void setOptype(ServiceOptype optype){ _body[KEY_OPTYPE] = (int)optype;}
        void setHost(Address host)
        {
            Json::Value val;
            val[KEY_HOST_IP] = host.first;
            val[KEY_HOST_PORT] = host.second;
            _body[KEY_HOST] = val;
        }
    };


    // 2.2.1 RpcResponse  -- recode + result
    class RpcResponse : public JsonResPonse
    {
    public:
        using ptr = std::shared_ptr<RpcResponse>;
        virtual bool check() override 
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false) 
            {
                ELOG("Rpc响应 -- Recode为空  或 Recode类型错误!");
                return false;
            }

            if (_body[KEY_RESULT].isNull() == true)
            {
                ELOG("Rpc响应 -- Result为空 或 Result类型错误!" );
                return false;
            }
            return true;
        }

        Json::Value result() { return _body[KEY_RESULT];}
        void setResult(const Json::Value &result) { _body[KEY_RESULT] = result; }
    };

    // 2.2.2 TopicResponse  -- recode
    class TopicResponse : public JsonResPonse 
    {
    public:
        using ptr = std::shared_ptr<TopicResponse>;
    };

    // 2.2.3 ServiceResponse  -- optype(因为将响应都整合了, 需要额外添加一个字段去识别 服务请求的不同响应)
    // 服务注册 + 上线 + 下线  -- recode + optype
    // 服务发现 -- recode + optype + method + hosts
    class ServiceResponse : public JsonResPonse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;
        // 检查
        virtual bool check() override 
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false) 
            {
                ELOG("服务响应 -- recode 或 recode类型错误!");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                ELOG("服务响应 -- optype为空 或 optype类型错误!");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() == (int)(ServiceOptype::SERVICE_DISCOVERY) &&
                (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false
                || _body[KEY_HOST].isNull() == true || _body[KEY_HOST].isArray() == false))
            {
                ELOG("服务响应 -- 服务地址信息出错!");
                return false;
            }
            return true;
        }

        ServiceOptype optype() { return (ServiceOptype)_body[KEY_OPTYPE].asInt();}
        std::string method() { return _body[KEY_METHOD].asString();}
        // 返回已经上线的服务信息
        std::vector<Address>  hosts()
        {
            std::vector<Address> addrs;
            int sz = _body[KEY_HOST].size();
            for(int i = 0; i < sz; i++)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addrs.push_back(addr);
            }
            return addrs;
        }

        void setOptype(ServiceOptype optype) {_body[KEY_OPTYPE] = (int)optype;}
        void setMethod(const std::string &method) { _body[KEY_METHOD] = method; }
        // 设置上线的服务地址信息
        void setHost(std::vector<Address> addrs) 
        {
            for (auto &addr : addrs) {
                Json::Value val;
                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(val);
            }
        }
    };

    // 消息工厂(简单工厂) -- 根据不同类型生产不同消息
    class MessageFactory
    {
    public:
        static BaseMessage::ptr create(MType type)
        {
            switch (type)
            {
                case MType::REQ_RPC : return std::make_shared<RpcRequest>();
                case MType::REQ_TOPIC : return std::make_shared<TopicRequest>();
                case MType::REQ_SERVICE : return std::make_shared<ServiceRequest>();
                case MType::RSP_RPC : return std::make_shared<RpcResponse>();
                case MType::RSP_TOPIC : return std::make_shared<TopicResponse>();
                case MType::RSP_SERVICE : return std::make_shared<ServiceResponse>();
                case MType::HEARTBEAT : return std::make_shared<HeartbeatMessage>();
            }
            return BaseMessage::ptr();
        }

        // 使用参数包来创建
        template<typename T, typename ...Args>
        static std::shared_ptr<T> create(Args&& ...args)
        {
            return std::make_shared<T>(std::forward(args)...);
        }
    };

}